package sysinfo

import (
	"deepseek-chat/internal/models"
	"fmt"
	"os/exec"
	"runtime"
	"strconv"
	"strings"
	"time"
)

var startTime = time.Now()

// GetSystemStatus gets system status information
func GetSystemStatus(activeConnections int) models.SystemStatus {
	var m runtime.MemStats
	runtime.ReadMemStats(&m)
	
	// CPU Info
	cpuInfo := models.CPUInfo{
		Usage: getCPUUsage(),
		Cores: runtime.NumCPU(),
		Model: getCPUModel(),
	}
	
	// Memory Info
	total, used, available := getSystemMemoryUsage()
	memInfo := models.MemoryInfo{
		Total:        total,
		Used:         used,
		Available:    available,
		Usage:        float64(used) / float64(total) * 100,
		TopProcesses: getTopMemoryProcesses(),
	}
	
	// Disk Info
	diskInfo := getDiskInfo()
	
	// Network Info
	networkInfo := models.NetworkInfo{
		Connections: activeConnections,
		Status:      "active",
	}
	
	return models.SystemStatus{
		CPU:     cpuInfo,
		Memory:  memInfo,
		Disk:    diskInfo,
		Network: networkInfo,
		Uptime:  time.Since(startTime).Seconds(),
	}
}

// GetAllProcesses gets all processes information
func GetAllProcesses() []models.ProcessInfo {
	if runtime.GOOS == "darwin" {
		return getMacOSAllProcesses()
	}
	return []models.ProcessInfo{}
}

// Helper functions (copied from original main.go and adapted)

func getCPUUsage() float64 {
	return float64(runtime.NumGoroutine()) / float64(runtime.NumCPU()) * 10
}

func getCPUModel() string {
	if runtime.GOOS == "darwin" {
		return getMacOSCPUModel()
	}
	return runtime.GOARCH + " processor"
}

func getMacOSCPUModel() string {
	cmd := `sysctl -n machdep.cpu.brand_string 2>/dev/null || echo "Unknown CPU"`
	if output, err := exec.Command("sh", "-c", cmd).Output(); err == nil {
		model := strings.TrimSpace(string(output))
		if model != "" && model != "Unknown CPU" {
			return model
		}
	}
	return "Apple Silicon / Intel CPU"
}

func getSystemMemoryUsage() (total, used, available uint64) {
	if runtime.GOOS == "darwin" {
		return getMacOSMemoryUsage()
	}
	total = 8 * 1024 * 1024 * 1024 
	used = total / 4               
	available = total - used
	return
}

func getMacOSMemoryUsage() (total, used, available uint64) {
	if output, err := exec.Command("sysctl", "-n", "hw.memsize").Output(); err == nil {
		if totalMem, err := strconv.ParseUint(strings.TrimSpace(string(output)), 10, 64); err == nil {
			total = totalMem
		}
	}
	
	if output, err := exec.Command("vm_stat").Output(); err == nil {
		lines := strings.Split(string(output), "\n")
		var pageSize, freePages, inactivePages uint64 = 4096, 0, 0
		
		for _, line := range lines {
			if strings.Contains(line, "Pages free:") {
				if parts := strings.Fields(line); len(parts) >= 3 {
					if val, err := strconv.ParseUint(strings.TrimSuffix(parts[2], "."), 10, 64); err == nil {
						freePages = val
					}
				}
			} else if strings.Contains(line, "Pages inactive:") {
				if parts := strings.Fields(line); len(parts) >= 3 {
					if val, err := strconv.ParseUint(strings.TrimSuffix(parts[2], "."), 10, 64); err == nil {
						inactivePages = val
					}
				}
			}
		}
		
		available = (freePages + inactivePages) * pageSize
		used = total - available
	}
	
	if total == 0 {
		total = 8 * 1024 * 1024 * 1024
		used = total / 4
		available = total - used
	}
	
	return
}

func getTopMemoryProcesses() []models.ProcessInfo {
	if runtime.GOOS == "darwin" {
		return getMacOSTopMemoryProcesses()
	}
	return []models.ProcessInfo{}
}

func getMacOSTopMemoryProcesses() []models.ProcessInfo {
	var processes []models.ProcessInfo
	cmd := "ps aux | sort -k4 -nr | head -6 | tail -5"
	if output, err := exec.Command("sh", "-c", cmd).Output(); err == nil {
		lines := strings.Split(strings.TrimSpace(string(output)), "\n")
		for _, line := range lines {
			if line == "" { continue }
			fields := strings.Fields(line)
			if len(fields) >= 11 {
				pid := fields[1]
				memUsage := fields[3]
				memSize := fields[5]
				name := strings.Join(fields[10:], " ")
				if len(name) > 50 { name = name[:50] + "..." }
				usage := 0.0
				if val, err := strconv.ParseFloat(memUsage, 64); err == nil { usage = val }
				processes = append(processes, models.ProcessInfo{
					Name:   name,
					PID:    pid,
					Memory: formatMemorySize(memSize),
					Usage:  usage,
				})
			}
		}
	}
	return processes
}

func getMacOSAllProcesses() []models.ProcessInfo {
	var processes []models.ProcessInfo
	cmd := "ps aux | sort -k4 -nr | tail -n +2"
	if output, err := exec.Command("sh", "-c", cmd).Output(); err == nil {
		lines := strings.Split(strings.TrimSpace(string(output)), "\n")
		for _, line := range lines {
			if line == "" { continue }
			fields := strings.Fields(line)
			if len(fields) >= 11 {
				pid := fields[1]
				memUsage := fields[3]
				memSize := fields[5]
				name := strings.Join(fields[10:], " ")
				usage := 0.0
				if val, err := strconv.ParseFloat(memUsage, 64); err == nil { usage = val }
				if usage > 0.1 {
					processes = append(processes, models.ProcessInfo{
						Name:   name,
						PID:    pid,
						Memory: formatMemorySize(memSize),
						Usage:  usage,
					})
				}
			}
		}
	}
	return processes
}

func formatMemorySize(sizeStr string) string {
	if size, err := strconv.ParseFloat(sizeStr, 64); err == nil {
		if size >= 1024*1024 {
			return fmt.Sprintf("%.1fGB", size/(1024*1024))
		} else if size >= 1024 {
			return fmt.Sprintf("%.1fMB", size/1024)
		} else {
			return fmt.Sprintf("%.0fKB", size)
		}
	}
	return sizeStr
}

func getDiskInfo() models.DiskInfo {
	total, used, available := getDiskUsage(".")
	usage := float64(used) / float64(total) * 100
	return models.DiskInfo{
		Total:     total,
		Used:      used,
		Available: available,
		Usage:     usage,
	}
}

func getDiskUsage(path string) (total, used, available uint64) {
	total = 100 * 1024 * 1024 * 1024
	used = 30 * 1024 * 1024 * 1024
	available = total - used
	return
}
